#include "common.h"

// #define _DEBUG
using namespace std;
struct Router all_router[MAXROUTERS];
int n_router;
int sockfd[MAXROUTERS];

// void Send(int fd, Message *message, int m_len)
// {
//     send(fd, (void *)message, m_len, 0);
// }

// int Recv(int fd, MessageR2A *message, void *payload)
// {
//     char buf[MAXLINE];
//     int recv_bytes = recv(fd, (void *)buf, MAXLINE, 0);
//     if (recv_bytes < 0)
//     {
//         perror("recvfrom failed:");
//     }
//     Message *msg = (Message *)buf;
//     if (msg->message_type != R2A)
//         return -1;
//     memcpy(message, buf, sizeof(MessageR2A));
//     if (message->length > 0 && payload)
//         memcpy(payload, buf + sizeof(MessageR2A), message->length);
//     return recv_bytes;
// }

void dv()
{

    for (int i = 0; i < n_router; ++i)
    {
        struct MessageA2RDv msg_s;
        struct MessageR2A msg_r(0);
        Rio_writen(sockfd[i], &msg_s, msg_s.len);
#ifdef _DEBUG
        printf("[INFO]: send dv to %d.\n", i);
#endif
        Rio_readn(sockfd[i], &msg_r, msg_r.len);
#ifdef _DEBUG
        printf("[INFO]: dv %d finished.\n", i);
#endif
    }
}
void update(int from, int to, int value)
{
    struct MessageA2RUpdate msg_s(from, to, value);
    struct MessageR2A msg_r(0);
    Rio_writen(sockfd[from], &msg_s, msg_s.len);
    Rio_readn(sockfd[from], &msg_r, msg_r.len);
}
void show(int id)
{
    struct MessageA2RShow msg_s;
    struct MessageR2A msg_r(0);

#ifdef _DEBUG
    printf("[INFO]: Send SHOW to router %d\n", id);
#endif

    Rio_writen(sockfd[id], &msg_s, msg_s.len);
    char output[MAXLINE];
    Rio_readn(sockfd[id], &msg_r, msg_r.len);
    Rio_readn(sockfd[id], output, msg_r.pl_len);

#ifdef _DEBUG
    printf("[INFO]: Recieve the reply of SHOW from router %d\n", id);
#endif
    output[msg_r.pl_len] = '\0';
    printf("%s", output);
}
void reset(int id)
{
}
void doit()
{
    char buffer[MAXLINE], command[10];

    while (1)
    {
        scanf("%s", buffer);
        char *pos = strchr(buffer, ':');
        if (pos == NULL)
        {
            if (!strcmp(buffer, "dv"))
            {
                // dv
                dv();
#ifdef _DEBUG
                puts("[INFO]: dv finished.");
#endif
            }
        }
        else
        {
            (*pos) = ' ';
            sscanf(buffer, "%s", command);
            if (!strcmp(command, "update"))
            {
                int from, to, value;
                sscanf(pos, "%d,%d,%d", &from, &to, &value);

                // printf("%d %d %d\n", from, to, value);
                update(alloc_id[from], alloc_id[to], value);
#ifdef _DEBUG
                puts("[INFO]: update finished.");
#endif
            }
            else if (!strcmp(command, "show"))
            {
                int id;
                sscanf(pos, "%d", &id);
                // printf("%d\n", id);
                show(alloc_id[id]);
#ifdef _DEBUG
                puts("[INFO]: show finished.");
#endif
            }
            else if (!strcmp(command, "reset"))
            {
            }
        }
    }
}
int main(int argc, char *argv[])
{
    setvbuf(stdout, NULL, _IONBF, 0);
    if (argc != 2)
    {
        puts("Usage: ./agent <router location file>");
        return 0;
    }
    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL)
    {
        puts("router location file not exist.");
        return 0;
    }
    fscanf(fp, "%d", &n_router);
    char buf[MAXLINE];
    for (int i = 0; i < n_router; ++i)
    {
        fscanf(fp, "%s", buf);
        all_router[i].set_router(buf, i);
    }
    fclose(fp);

    for (int i = 0; i < n_router; ++i)
    {
        sockfd[i] = socket(AF_INET, SOCK_STREAM, 0);
        while (connect(sockfd[i], (struct sockaddr *)&all_router[i].router_addr, all_router[i].addr_len) < 0)
            ;
        int AGENT = -1;
        Rio_writen(sockfd[i], &AGENT, sizeof(int));
// {
//     perror("connect failed");
//     exit(EXIT_FAILURE);
// }
#ifdef _DEBUG
        printf("[INFO]: build connect to router %d succesfully!\n", i);
#endif
    }
    doit();
    for (int i = 0; i < n_router; ++i)
        close(sockfd[i]);
    return 0;
}